﻿using System;

namespace Sine
{
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Threading;
    using System.Windows.Media;
    using AHD.MyNes.Nes;
    using mynessl.APU;

    public class NesMediaStreamSource : MediaStreamSource
    {
        private readonly Stream streamSave;
        private MediaStreamDescription _audioDesc;
        public long _currentPosition;
        public long _currentTimeStamp;
        private Dictionary<MediaSampleAttributeKeys, string> _emptySampleDict = new Dictionary<MediaSampleAttributeKeys, string>();
        public long _startPosition;
        private Stream _stream;
        public WaveFormatEx _waveFormat;
        private const int BitsPerSample = 0x10;
        private const int ByteRate = 0x2b110;
        private const int ChannelCount = 2;
        private MediaStreamSample msSamp;
        private bool PROCEED;
        private const int SampleRate = 0xac44;

        public NesMediaStreamSource(Stream stream)
        {
            this.streamSave = stream;
            base.AudioBufferLength = 20;
            this._waveFormat = new WaveFormatEx();
            this._waveFormat.BitsPerSample = 0x8;
            this._waveFormat.AvgBytesPerSec = 44100;
            this._waveFormat.Channels = 1;
            this._waveFormat.BlockAlign = 1;
            this._waveFormat.ext = null;
            this._waveFormat.FormatTag = 1;
            this._waveFormat.SamplesPerSec = 44100;
            this._waveFormat.Size = 0;
            this._waveFormat.ValidateWaveFormat();
            this._stream = new MemoryStream();
            if (streamSave != null)
            {
                //Write header
                WriteHeader();
            }
        }

        private void WriteHeader() 
        {
            byte[] fmtHeader = _waveFormat.ToByteArray(streamSave);
            long pos = streamSave.Position;
            streamSave.Seek(0, SeekOrigin.Begin);
            streamSave.Write(fmtHeader, 0, fmtHeader.Length);
            streamSave.Seek(pos, SeekOrigin.Begin);
            streamSave.Flush();
        }

        protected override void CloseMedia()
        {
            this._startPosition = this._currentPosition = 0L;
            this._audioDesc = null;
        }

        protected override void GetDiagnosticAsync(MediaStreamSourceDiagnosticKind diagnosticKind)
        {
            throw new NotImplementedException();
        }

        protected override void GetSampleAsync(MediaStreamType mediaStreamType)
        {
            this.PROCEED = true;
        }

        protected override void OpenMediaAsync()
        {
            this._startPosition = this._currentPosition = 0L;
            Dictionary<MediaStreamAttributeKeys, string> dictionary = new Dictionary<MediaStreamAttributeKeys, string>();
            Dictionary<MediaSourceAttributesKeys, string> dictionary2 = new Dictionary<MediaSourceAttributesKeys, string>();
            List<MediaStreamDescription> list = new List<MediaStreamDescription>();
            dictionary[0] = this._waveFormat.ToHexString();
            MediaStreamDescription description = new MediaStreamDescription(0, dictionary);
            this._audioDesc = description;
            list.Add(this._audioDesc);
            dictionary2[MediaSourceAttributesKeys.Duration] = TimeSpan.FromMinutes(0.0).Ticks.ToString(CultureInfo.InvariantCulture);
            dictionary2[MediaSourceAttributesKeys.CanSeek] = false.ToString();
            base.ReportOpenMediaCompleted(dictionary2, list);
        }

        protected override void SeekAsync(long seekToTime)
        {
            base.ReportSeekCompleted(seekToTime);
        }

        protected override void SwitchMediaStreamAsync(MediaStreamDescription mediaStreamDescription)
        {
            throw new NotImplementedException();
        }

        public byte[] dropbuffer=new byte[0];
        private int dropcount = 0;

        public void write(byte[] bytes, int blaa, int count)
        {
            lock (dropbuffer)
            {
                dropbuffer = bytes;
                dropcount = count;
            }
        }

        public void Drop()
        {
            lock (dropbuffer)
            {
                this._stream.Write(dropbuffer, 0, dropcount);  
                if (streamSave!=null)
                {
                    streamSave.Write(dropbuffer, 0, dropcount);
                    WriteHeader();
                }
            }
            this.msSamp = new MediaStreamSample(this._audioDesc, this._stream, this._currentPosition, (long)dropcount, this._currentTimeStamp, this._emptySampleDict);
            if (this.PROCEED)
            {
                base.ReportGetSampleCompleted(this.msSamp);
                this.PROCEED = false;
            }
            this._currentPosition += dropcount;
            this._currentTimeStamp += this._waveFormat.AudioDurationFromBufferSize((uint)dropcount);

        }
    }
}
